#include "parse8583.h"
#define HEADINDEX   -1

FieldInfo* fieldInfo[3] = {&icbcInfo, &petroInfo, &unionInfo};

Parse8583::Parse8583(QWidget *parent)
    : QWidget(parent)
{
    //this->resize(420, 580);
    this->setFixedSize(420, 570);
    this->setWindowTitle("8583 解 包 工 具");

    dataLabel = new QLabel(this);
    dataLabel->setGeometry(12, 10, 100, 20);
    dataLabel->setText("原 始 数 据：");

    dataEdit = new QTextEdit(this);
    dataEdit->setGeometry(10, 30, 400, 180);

    resultLabel = new QLabel(this);
    resultLabel->setGeometry(12, 220, 100, 20);
    resultLabel->setText("解 析 结 果：");

    resultEdit = new QTextEdit(this);
    resultEdit->setGeometry(10, 240, 400, 260);
    //resultEdit->setReadOnly(true);

    parseButton = new QPushButton(this);
    parseButton->setGeometry(245, 520, 80, 30);
    parseButton->setText("解  析");
    connect(parseButton, SIGNAL(clicked()), this, SLOT(currMessageParse()));

    prevButton = new QPushButton(this);
    prevButton->setGeometry(160, 520, 80, 30);
    prevButton->setText("前一包");
    connect(prevButton, SIGNAL(clicked()), this, SLOT(prevMessageParse()));

    nextButton = new QPushButton(this);
    nextButton->setGeometry(330, 520, 80, 30);
    nextButton->setText("后一包");
    connect(nextButton, SIGNAL(clicked()), this, SLOT(nextMessageParse()));

    versionBox = new QGroupBox(this);
    versionBox->setGeometry(10, 510, 140, 45);
    versionBox->setTitle("报文版本");

    versionCombo = new QComboBox(versionBox);
    versionCombo->setGeometry(10, 15, 120, 20);
    versionCombo->insertItem(0, "工商银行");
    versionCombo->insertItem(1, "中国石油");
    versionCombo->insertItem(2, "中国银联");

    history.clear();
    maxHistorySize = 5;
    currentIndex = 0;
    prevButton->setEnabled(false);
    nextButton->setEnabled(false);
    connect(this, SIGNAL(parseDone()), this, SLOT(displayResult()));
}

Parse8583::~Parse8583()
{

}

void Parse8583::currMessageParse()
{
    QString temp = dataEdit->toPlainText();
    temp.remove(QChar(' '));
    temp.remove(QChar('\n'));
    if(temp.isEmpty())
        return;

    history.append(QPair<int, QString>(versionCombo->currentIndex(), temp));
    if(history.size() > maxHistorySize)
        history.removeFirst();
    currentIndex = history.size() - 1;
    dataEdit->setText(history.at(currentIndex).second);
    adjustButtonStatus();
    parseData(fieldInfo[history.at(currentIndex).first], history.at(currentIndex).second);
}

void Parse8583::prevMessageParse()
{
    if(currentIndex == 0)
        return;
    currentIndex--;
    dataEdit->setText(history.at(currentIndex).second);
    versionCombo->setCurrentIndex(history.at(currentIndex).first);
    adjustButtonStatus();
    parseData(fieldInfo[history.at(currentIndex).first], history.at(currentIndex).second);
}

void Parse8583::nextMessageParse()
{
    if(currentIndex == history.size() - 1)
        return;
    currentIndex++;
    dataEdit->setText(history.at(currentIndex).second);
    versionCombo->setCurrentIndex(history.at(currentIndex).first);
    adjustButtonStatus();
    parseData(fieldInfo[history.at(currentIndex).first], history.at(currentIndex).second);
}

int Parse8583::parseData(FieldInfo *pFieldInfo, QString originalData)
{
    domain.clear();
    errMsg.clear();
    BitMap.fill(false);
    parseSuccess = false;

    int dataLen = originalData.size()/2;
    int len = 2 + pFieldInfo->headLen + 10;
    if(dataLen <= len)
    {
        errMsg = QString("报文太短！\n最小长度：%1").arg(len);
        emit this->parseDone();
        return -1;
    }
    unsigned char *data = new unsigned char[dataLen];
    dsptohex(originalData.toLocal8Bit().data(), (char*)data, dataLen);

    int pos = 0;
    totalLen = data[pos]*256 + data[pos+1];
    pos += 2;
    if(totalLen+2 != dataLen)
    {
        errMsg = QString("报文长度错误！\n标明长度：%1\n实际长度：%2").arg(totalLen).arg(dataLen-2);
        emit this->parseDone();
        return -1;
    }

    domain.insert(HEADINDEX, QByteArray((char*)data+pos, pFieldInfo->headLen));
    pos += pFieldInfo->headLen;

    domain.insert(pFieldInfo->szFieldDeatil[0].nField, QByteArray((char*)data+pos, pFieldInfo->szFieldDeatil[0].nMaxSize/2));
    pos += pFieldInfo->szFieldDeatil[0].nMaxSize/2;

    len = parseBitMap(data+pos);
    if(len < 0)
        return -1;
    if(pos + len > dataLen)
    {
        errMsg = QString("解析位图出错！\n起始偏移：%1\n位图长度:%2").arg(pos).arg(len);
        emit this->parseDone();
        return -1;
    }
    domain.insert(1, QByteArray((char*)data+pos, len));
    pos += len;

    for(int i = 2; i < pFieldInfo->nFieldInfoNum; i++)
    {
        if(!BitMap.testBit(i-1))//indexs of QBitArray start with 0 while indexs of domain start with 1;
            continue;
        switch(pFieldInfo->szFieldDeatil[i].nType)
        {
            case FIX_ASC:
            {
                len = pFieldInfo->szFieldDeatil[i].nMaxSize;
                break;
            }
            case LL_ASC:
            {
                len = QByteArray((char*)data+pos, 1).toHex().toInt();
                pos += 1;
                break;
            }
            case LLL_ASC:
            {
                len = QByteArray((char*)data+pos, 2).toHex().toInt();
                pos += 2;
                break;
            }
            case FIX_BCD:
            {
                len = (pFieldInfo->szFieldDeatil[i].nMaxSize + 1) / 2;
                break;
            }
            case LL_BCD:
            {
                len = (QByteArray((char*)data+pos, 1).toHex().toInt()+1) / 2;
                pos += 1;
                break;
            }
            case LLL_BCD:
            {
                len = (QByteArray((char*)data+pos, 2).toHex().toInt()+1) / 2;
                pos += 2;
                break;
            }
        }
        if(pos + len > dataLen)
        {
            errMsg = QString("解析第%1域出错！\n起始偏移：%2\n末尾偏移：%3\n报文总长：%4").arg(i).arg(pos).arg(pos+len).arg(totalLen);
            emit this->parseDone();
            return -1;
        }
        domain.insert(i, QByteArray((char*)data+pos, len));
        pos += len;
    }

    parseSuccess = true;
    emit this->parseDone();
    return 0;
}

//解析位图，成功返回位图长度
int Parse8583::parseBitMap(unsigned char *bitMap)
{
    int len;
    if(bitMap == NULL)
        return -1;

    if((bitMap[0] & 0x80) == 0)
        len = 8;
    else
        len = 16;
    BitMap = QBitArray(len*8);

    for(int byte = 0; byte < len; byte++)
    {
        for(int bit = 0; bit < 8; bit++)
        {
            if(((*(bitMap+byte)) & (0x80>>bit)) != 0)
                BitMap.setBit(byte*8+bit);
        }
    }
    return len;
}

void Parse8583::adjustButtonStatus()
{
    if(currentIndex == history.size() - 1)
        nextButton->setEnabled(false);
    else
        nextButton->setEnabled(true);

    if(currentIndex == 0)
        prevButton->setEnabled(false);
    else
        prevButton->setEnabled(true);
}

/*void Parse8583::setOutputStyle(bool state)
{
    if(state)
        outputStyle = APPARENT;
    else
        outputStyle = INTENSION;
    this->displayResult();
}*/

void Parse8583::displayResult()
{
    resultEdit->clear();
    if(!parseSuccess)
        resultEdit->insertPlainText("解析失败："+errMsg+"\n");

    resultEdit->insertPlainText("消息头：" + QString(domain.value(HEADINDEX).toHex()) + "\n");
    resultEdit->insertPlainText("消息类型：" + QString(domain.value(0).toHex()) + "\n");

    FieldInfo *pFieldInfo = fieldInfo[history.at(currentIndex).first];
    QString result;
    for(int i = 1; i < pFieldInfo->nFieldInfoNum; i++)
    {
        if(!BitMap.testBit(i-1))
            continue;
        result = QString("%1域: ").arg(i, 2, 10, QChar('0'));
        if(domain.contains(i))
        {
            if(pFieldInfo->szFieldDeatil[i].nType > 3)  //BCD
                result += QString(domain.value(i).toHex().toUpper());
            else
                result += ("\"" + QString(domain.value(i)) + "\"");
        }
        resultEdit->insertPlainText(result + "\n");
    }
}

void Parse8583::dsptohex(char *dsp, char *hex, int hex_count)
{
    int i;
    char ch;

    for(i = 0; i < hex_count; i++)
    {
        ch = dsp[i * 2];
        if(islower(ch))
            ch = toupper(ch);

        hex[i] = ((ch >= 0x41) ? ch - 0x41 + 10 : ch - 0x30);
        hex[i] = hex[i] << 4;

        ch = dsp[i * 2 + 1];
        if(islower(ch))
            ch = toupper(ch);

        hex[i] += ((ch >= 0x41) ? ch - 0x41 + 10 : ch - 0x30);
    }
}

void Parse8583::hextodsp(char *hex, char *dsp, int hex_count)
{
    int i;
    char ch;
    for(i = 0; i < hex_count; i++)
    {
        ch = (hex[i] & 0xf0) >> 4;
        dsp[i * 2] = (ch > 9) ? (ch + 0x41 - 10) : (ch + 0x30);
        ch = hex[i] & 0x0f;
        dsp[i * 2 + 1] = (ch > 9) ? (ch + 0x41 - 10) : (ch + 0x30);
    }
}
